// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#pragma once

#include <nebula/compute/api_vector.h>
#include <nebula/compute/cast.h>           // IWYU pragma: export
#include <nebula/compute/cast_internal.h>  // IWYU pragma: export
#include <nebula/compute/kernels/common_internal.h>
#include <nebula/compute/kernels/util_internal.h>

namespace nebula {
namespace compute {
namespace internal {

template <typename OutType, typename InType, typename Enable = void>
struct CastFunctor {};

// No-op functor for identity casts
template <typename O, typename I>
struct CastFunctor<
    O, I, enable_if_t<std::is_same<O, I>::value && is_parameter_free_type<I>::value>> {
  static turbo::Status Exec(KernelContext*, const ExecSpan&, ExecResult*) {
    return turbo::OkStatus();
  }
};

turbo::Status CastFromExtension(KernelContext* ctx, const ExecSpan& batch, ExecResult* out);

// Utility for numeric casts
void CastNumberToNumberUnsafe(Type::type in_type, Type::type out_type,
                              const ArraySpan& input, ArraySpan* out);

// ----------------------------------------------------------------------
// Dictionary to other things

turbo::Status UnpackDictionary(KernelContext* ctx, const ExecSpan& batch, ExecResult* out);

turbo::Status OutputAllNull(KernelContext* ctx, const ExecSpan& batch, ExecResult* out);

turbo::Status CastFromNull(KernelContext* ctx, const ExecSpan& batch, ExecResult* out);

// Adds a cast function where CastFunctor is specialized and the input and output
// types are parameter free (have a type_singleton).
template <typename InType, typename OutType>
void AddSimpleCast(InputType in_ty, OutputType out_ty, CastFunction* func) {
  KCHECK_OK(func->add_kernel(InType::type_id, {in_ty}, out_ty,
                            CastFunctor<OutType, InType>::Exec));
}

turbo::Status ZeroCopyCastExec(KernelContext* ctx, const ExecSpan& batch, ExecResult* out);

void AddZeroCopyCast(Type::type in_type_id, InputType in_type, OutputType out_type,
                     CastFunction* func);

// OutputType::Resolver that returns a type the type from CastOptions
turbo::Result<TypeHolder> ResolveOutputFromOptions(KernelContext* ctx,
                                            const std::vector<TypeHolder>& args);

TURBO_EXPORT extern OutputType kOutputTargetType;

// Add generic casts to out_ty from:
// - the null type
// - dictionary with out_ty as given value type
// - extension types with a compatible storage type
void AddCommonCasts(Type::type out_type_id, OutputType out_ty, CastFunction* func);

}  // namespace internal
}  // namespace compute
}  // namespace nebula
